class Vector {
    protected _data: number[];

    /**
     * 向量类
     * @param data 数字数组
     */
    constructor(data: number[]) {
        // 初始化向量数据
        this._data = data;
    }

    /** 获取向量维度 */
    get dimension() {
        return this._data.length;
    }

    /** 向量的模 */
    get norm() {
        return Math.hypot(...this._data);
    }

    getItem(i: number) {
        return this._data[i];
    }

    /**
     * 标准化单位向量
     * @returns 
     */
    normalize() {
        const norm = this.norm;
        if (norm === 0) {
            throw new Error('Cannot normalize the zero vector');
        }
        const normalizedData = this._data.map(x => x / norm);
        return new Vector(normalizedData);
    }

    /**
     * 标量与向量乘法运算
     * @param n 
     * @returns 
     */
    mul(n: number) {
        return new Vector(this._data.map(x => x * n));
    }

    /**
     * 向量的加法运算
     * @param another 
     * @returns 
     */
    add(another: Vector) {
        if (this.dimension !== another.dimension) {
            throw new Error('Cannot add vectors of different dimensions');
        }
        const sumData = this._data.map((x, i) => x + another._data[i]);
        return new Vector(sumData);
    }

    /**
     * 向量的减法运算
     * @param another 
     * @returns 
     */
    sub(another: Vector) {
        if (this.dimension !== another.dimension) {
            throw new Error('Cannot subtract vectors of different dimensions');
        }
        const diffData = this._data.map((x, i) => x - another._data[i]);
        return new Vector(diffData);
    }

    /**
     * 两个向量的点乘和；
     * 若结果 = 0，则两向量互相垂直 。
     * 若结果 < 0 ，则两向量夹角大于90°。
     * 若结果 >0 ，则两向量夹角小于 90°。
     * @param another 
     * @returns 标量
     */
    dotMul(another: Vector) {
        if (this.dimension !== another.dimension) {
            throw new Error('Cannot dot multiply vectors of different dimensions');
        }
        const dotProduct = this._data.reduce((acc, x, i) => acc + x * another._data[i], 0);
        return dotProduct;
    }

    /**
     * 向量取正
     * @returns 
     */
    pos() {
        return this.mul(1);
    }

    /**
     * 向量取负
     * @returns 
     */
    neg() {
        return this.mul(-1);
    }

    /**
     * 零向量
     * @param dimension 
     * @returns 
     */
    static zero(dimension: number) {
        return new Vector(new Array(dimension).fill(0));
    }

    toString() {
        let str = '';
        for (let i = 0; i < this._data.length; i++) {
            if (i !== this._data.length - 1) {
                str += `${this._data[i]},`;
            } else {
                str += this._data[i];
            }
        }
        return `Vector(${str})`;
    }
}

export default Vector;
